#include "TFunctionSqrtOfThree.h"
#include "math.h"
//#define SQRT_DEBUG


TFunctionSqrtOfThree::TFunctionSqrtOfThree()
{
}


TFunctionSqrtOfThree::~TFunctionSqrtOfThree()
{
}

void TFunctionSqrtOfThree::run()
{
	qDebug() << "func sqrt of Three is starting...";
	reset();
	m_config = eConfig_SqrtOfThree_begin;
	int turn = 0;
	do {
		switch (m_config) {
		case eConfig_SqrtOfThree_begin: {
			if (0 == m_cells[m_index]) {
				m_cells[m_index] = '@';
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_index++;
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_cells[m_index] = '1';
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_new;
			}
		}
										break;
		case eConfig_SqrtOfThree_new: {
			if ('@' == m_cells[m_index]) {
				m_index++;
				m_config = eConfig_SqrtOfThree_mark_digits;
			}
			else {
				m_index--;
			}
#ifdef SQRT_DEBUG
			sendUpdateSignal();
#endif
		}
									  break;
		case eConfig_SqrtOfThree_mark_digits: {
			if ('0' == m_cells[m_index] || '1' == m_cells[m_index]) {
				m_index++;
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_cells[m_index] = 'x';
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_index++;
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
			}
			else if (0 == m_cells[m_index]) {
				m_index++;
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_cells[m_index] = 'z';
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_index++;
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_index++;
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_cells[m_index] = 'r';
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				prSth('r');
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_find_x;
			}
		}
											  break;
		case		eConfig_SqrtOfThree_find_x: {
			if (matchSth('x')) {
				E();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_first_r;
			}
			else if (matchSth('@')) {
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_find_digits;
			}
			else {
				L();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				L();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
			}
		}
												break;
		case		eConfig_SqrtOfThree_first_r: {
			if (matchSth('r')) {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_last_r;
			}
			else {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
			}
		} break;
		case		eConfig_SqrtOfThree_last_r: {
			if (matchSth('r')) {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
			}
			else if (matchSth('\0')) {
				prSth('r');
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				prSth('r');
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_find_x;
			}
		} break;
		case		eConfig_SqrtOfThree_find_digits: {
			if (matchSth('@')) {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_find_1st_digit;
			}
			else {
				L();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				L();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
			}
		} break;
		case		eConfig_SqrtOfThree_find_1st_digit: {
			if (matchSth('x') || matchSth('y')) {
				L();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_found_1st_digit;
			}
			else if (matchSth('z')) {
				L();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_found_2nd_digit;
			}
			else if (matchSth('\0')) {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
			}
		} break;
		case		eConfig_SqrtOfThree_found_1st_digit: {
			if (matchSth('0')) {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_add_zero;
			}
			else if (matchSth('1')) {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_find_2nd_digit;
			}
		} break;
		case		eConfig_SqrtOfThree_find_2nd_digit: {
			if (matchSth('x') || matchSth('y')) {
				L();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_found_2nd_digit;
			}
			else if (matchSth('\0')) {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif				
			}
		} break;
		case		eConfig_SqrtOfThree_found_2nd_digit: {
			if (matchSth('0')) {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_add_zero;
			}
			else if (matchSth('1')) {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_add_one;
			}
			else if (matchSth('\0')) {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_add_one;
			}
		} break;
		case		eConfig_SqrtOfThree_add_zero: {
			if (matchSth('r')) {
				prSth('s');
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_add_finished;
			}
			else if (matchSth('u')) {
				prSth('v');
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_add_finished;
			}
			else {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
			}
		} break;
		case		eConfig_SqrtOfThree_add_one: {
			if (matchSth('r')) {
				prSth('v');
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_add_finished;
			}
			else if (matchSth('u')) {
				prSth('s');
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
				m_config = eConfig_SqrtOfThree_carry;
			}
			else {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif				
			}
		} break;
		case		eConfig_SqrtOfThree_carry: {
			if (matchSth('r')) {
				prSth('u');
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_add_finished;
			}
			else if (matchSth('\0')) {
				prSth('u');
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_new_digit_is_zero;
			}
			else if (matchSth('u')) {
				prSth('r');
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
			}
		} break;
		case		eConfig_SqrtOfThree_add_finished: {
			if (matchSth('@')) {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_erase_old_x;
			}
			else {
				L();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				L();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif				
			}
		} break;
		case		eConfig_SqrtOfThree_erase_old_x: {
			if (matchSth('x')) {
				E();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				L();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				L();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_print_new_x;
			}
			else if (matchSth('z')) {
				prSth('y');
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				L();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				L();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_print_new_x;
			}
			else {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif				
			}
		} break;
		case		eConfig_SqrtOfThree_print_new_x: {
			if (matchSth('@')) {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_erase_old_y;
			}
			else if (matchSth('y')) {
				prSth('z');
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_find_digits;
			}
			else if (matchSth('\0')) {
				prSth('x');
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_find_digits;
			}
		} break;
		case		eConfig_SqrtOfThree_erase_old_y: {
			if (matchSth('y')) {
				E();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				L();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				L();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_print_new_y;
			}
			else {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
			}
		} break;
		case			eConfig_SqrtOfThree_print_new_y: {
			if (matchSth('@')) {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_find_tbd_digit;
			}
			else {
				prSth('y');
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_reset_new_x;
			}
		} break;
		case eConfig_SqrtOfThree_find_tbd_digit: {
			if (matchSth(0)) {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_find_last_r;
			}
			else {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
			}
		}
												 break;
		case eConfig_SqrtOfThree_find_last_r: {
			if (matchSth(0)) {
				L();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				L();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_check_res;
			}
			else {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
			}
		}
											  break;
		case eConfig_SqrtOfThree_check_res: {
			if (matchSth('u') || matchSth('v')) {
				L();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				L();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_check_2_nd_digit;
			}
			else if (matchSth('r') || matchSth('s')) {
				m_config = eConfig_SqrtOfThree_new_digit_is_one;
			}
		}
											break;
		case eConfig_SqrtOfThree_check_2_nd_digit: {
			if (matchSth('u') || matchSth('v')) {
				m_config = eConfig_SqrtOfThree_new_digit_is_zero;
			}
			else if (matchSth('r') || matchSth('s')) {
				m_config = eConfig_SqrtOfThree_new_digit_is_one;
			}
		}
												   break;
		case			eConfig_SqrtOfThree_reset_new_x: {
			if (matchSth('\0')) {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				prSth('x');
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_flag_result_digits;
			}
			else {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
			}
		} break;
		case			eConfig_SqrtOfThree_flag_result_digits: {
			if (matchSth('s')) {
				prSth('t');
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_unflag_result_digits;
			}
			else if (matchSth('v')) {
				prSth('w');
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_unflag_result_digits;
			}
			else {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
			}
		} break;
		case			eConfig_SqrtOfThree_unflag_result_digits: {
			if (matchSth('s')) {
				prSth('r');
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif				
			}
			else if (matchSth('v')) {
				prSth('u');
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
			}
			else {
				m_config = eConfig_SqrtOfThree_find_digits;
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
			}
		} break;
		case		eConfig_SqrtOfThree_new_digit_is_zero: {
			if (matchSth('@')) {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_print_zero_digit;
			}
			else {
				L();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
			}
		} break;
		case		eConfig_SqrtOfThree_print_zero_digit: {
			if (matchSth('0') || matchSth('1')) {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				E();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif				
			}
			else if (matchSth(0)) {
				prSth('0');
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_cleanup;
			}
		} break;
		case		eConfig_SqrtOfThree_new_digit_is_one: {
			if (matchSth('@')) {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_print_one_digit;
			}
			else {
				L();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
			}
		} break;
		case		eConfig_SqrtOfThree_print_one_digit: {
			if (matchSth('0') || matchSth('1')) {
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				E();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif				
			}
			else if (matchSth(0)) {
				prSth('1');
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				m_config = eConfig_SqrtOfThree_cleanup;
			}
		} break;
		case		eConfig_SqrtOfThree_cleanup: {
			if (matchSth(0)) {
				m_config = eConfig_SqrtOfThree_new;
			}
			else {
				E();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
				R();
#ifdef SQRT_DEBUG
				sendUpdateSignal();
#endif
			}
		} break;
		default:
			break;
		}
		float res = calResult();
		//qDebug() << "At "<<turn << " turn:  " <<"res: "<<res<<", power of res is :"<< powf(res,2)<<", abs|2-res^2|="<<abs(2-powf(res,2));
		turn++;
		if (abs(3 - powf(res, 2)) < 2e-8) {
			qDebug() << "final result:";
			qDebug() << "At " << turn << " turn:  " << "res: " << res << ", power of res is :" << powf(res, 2) << ", abs|3-res^2|=" << abs(3 - powf(res, 2));
			//printf("res is %lf\r\n", res);
			qDebug("res is %lf\r\n", res);
			qDebug("sqrt(3) = %lf, abs(3-pow(sqrt(2),2) = %lf\r\n", sqrt(3), abs(3-pow(sqrt(3),2)));
			break;
		}
	} while (m_index < 1020);
	qDebug("index = %d\r\n", m_index);
}

double TFunctionSqrtOfThree::calResult()
{
	double sum = 0;
	int index = m_prevIndex-10;
	do {
		index++;
	} while (m_cells[index] != '@'&&index<200&& index >50);
	if (m_cells[index] == '@') {
		index++;
	}
	else {
		return 0.0;
	}
	int i = 0;
	do {
		if (m_cells[index] == '1') {
			sum += 1.0 / (pow(2.0, i));
		}
		i++;
		index += 2;
	} while (m_cells[index] == '0' || m_cells[index] == '1');
	return sum;
}
